#include "sd.h"
#include "config.h"

static int sd_initialised = 0;
/**
 * Initialises a sd interface
 *
 * @param[in]  sd  the interface which should be initialised
 *
 * @return  0 : on success,  otherwise is error
 */
int32_t hal_sd_init(sd_dev_t *sd)
{
	PORT_Init(PORTB, PIN1, PORTB_PIN1_SD_CLK, 0);
    PORT_Init(PORTB, PIN2, PORTB_PIN2_SD_CMD, 1);
    PORT_Init(PORTB, PIN3, PORTB_PIN3_SD_D0,  1);
    PORT_Init(PORTB, PIN4, PORTB_PIN4_SD_D1,  1);
    PORT_Init(PORTB, PIN5, PORTB_PIN5_SD_D2,  1);
    PORT_Init(PORTB, PIN6, PORTB_PIN6_SD_D3,  1);
	sd->port = 0;
	sd->priv = NULL;
	sd->config.freq = 50000000;
	sd_initialised = 1;
    return SDIO_Init(50000000);
}

/**
 * Read sd blocks
 *
 * @param[in]   sd        the interface which should be read
 * @param[out]  data      pointer to the buffer which will store incoming data
 * @param[in]   blk_addr  sd blk addr
 * @param[in]   blks      sd blks
 * @param[in]   timeout   timeout in milisecond
 *
 * @return  0 : on success,  otherwise is error
 */
int32_t hal_sd_blks_read(sd_dev_t *sd, uint8_t *data, uint32_t blk_addr,
                         uint32_t blks, uint32_t timeout)
{
	if (data == NULL || 0 == sd_initialised)
		return -1;
	
	if (blks == 1)
	{
		SDIO_BlockRead(blk_addr, (uint32_t *)data);
	}
	else
	{
		SDIO_MultiBlockRead(blk_addr, blks, (uint32_t *)data);
	}
	return 0;
}

/**
 * Write sd blocks
 *
 * @param[in]  sd        the interface which should be wrote
 * @param[in]  data      pointer to the buffer which will store incoming data
 * @param[in]  blk_addr  sd blk addr
 * @param[in]  blks      sd blks
 * @param[in]  timeout   timeout in milisecond
 *
 * @return  0 : on success,  otherwise is error
 */
int32_t hal_sd_blks_write(sd_dev_t *sd, uint8_t *data, uint32_t blk_addr,
                          uint32_t blks, uint32_t timeout)
{
	if (data == NULL || 0 == sd_initialised)
		return -1;
	
	if (blks == 1)
	{
		SDIO_BlockWrite(blk_addr, (uint32_t *)data);
	}
	else
	{
		SDIO_MultiBlockWrite(blk_addr, blks, (uint32_t *)data);
	}
	return 0;
}

/**
 * Erase sd blocks
 *
 * @param[in]  sd              the interface which should be erased
 * @param[in]  blk_start_addr  sd blocks start addr
 * @param[in]  blk_end_addr    sd blocks end addr
 *
 * @return  0 : on success,  otherwise is error
 */
int32_t hal_sd_erase(sd_dev_t *sd, uint32_t blk_start_addr, uint32_t blk_end_addr)
{
	return 0;
}

/**
 * Get sd state
 *
 * @param[in]   sd    the interface which should be got state
 * @param[out]  stat  pointer to the buffer which will store incoming state data
 *
 * @return  0 : on success,  otherwise is error
 */
int32_t hal_sd_stat_get(sd_dev_t *sd, hal_sd_stat *stat)
{
	if(sd_initialised)
		*stat = SD_STAT_TRANSFER;
	else
		*stat = SD_STAT_RESET;
	return 0;
}

/**
 * Get sd info
 *
 * @param[in]   sd    the interface which should be got info
 * @param[out]  stat  pointer to the buffer which will store incoming info data
 *
 * @return  0 : on success,  otherwise is error
 */
int32_t hal_sd_info_get(sd_dev_t *sd, hal_sd_info_t *info)
{
	info->blk_size = SD_cardInfo.CardBlockSize;
	info->blk_nums = SD_cardInfo.CardCapacity / 512;
	return 0;
}

/**
 * Deinitialises a sd interface
 *
 * @param[in]  sd  the interface which should be Deinitialised
 *
 * @return  0 : on success,  otherwise is error
 */
int32_t hal_sd_finalize(sd_dev_t *sd)
{
	return 0;
}
